Skip to main content

什么是闭包?

闭包的概念

简单来说,「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包。

函数内部能访问到的变量是指除了全局变量和当前函数内部变量之外的变量。

闭包不是函数,闭包是一种语言特性。有些语言不支持闭包,因此它的函数不能访问自由变量。

举例法

  • 典型的闭包是一个函数 A 内声明并返回一个函数 B 供外部使用,函数 B 内用到了 A 内部的局部变量或者形参。相互引用导致局部作用域不被释放一起构成闭包。

子函数不返回是否还是闭包?

是的,闭包跟 return 没有任何关系,函数 B 不一定直接返回,只要 B 能够被再次调用,都构成闭包。

比如 A 返回的是一个对象,而函数 B 是对象的属性。或者函数 B 能在 setTimeout 延时结束时的触发。

示例 1:

函数 B 不一定直接返回,只要 B 能够被再次调用,都构成闭包

function foo() {
var a = 1
function bar() {
console.log(a)
}
window.bar = bar
}

foo()
bar() //1

示例 2:

A 返回的是一个对象,而函数 B 是对象的属性。

function foo(){
var a= 1
function bar(){
console.log(a)
}
return {a:bar}
}

obj = foo ()
obj.a() //1

示例 3:

函数 B 能在 setTimeout 延时结束时的触发。

for (var i = 0; i < 3; i++){
!function(i){
setTimeout(() => {
console.log(i); // 这时打印出来的是 0、1、2 }, 1000); }(i) } //打印出来的是 0、1、2
})
}()
}

子函数引用的是爷爷级属性是否还是闭包?

只要引用了父级的作用域链上变量都可以构成闭包

闭包的用途(闭包解决了什么问题)

  • 一个是可以读取函数内部的变量

  • 让这些变量的值始终保持在内存中

    !(function () {
    var lives = 50
    window.奖励一条命 = function () {
    lives += 1
    console.log(lives)
    }
    window.死一条命 = function () {
    lives -= 1
    console.log(lives)
    }
    })()

    window.死一条命()
    //49

闭包的好处

可以重复使用变量,并且不会造成变量污染

全局变量可以重复使用,但是容易造成变量污染。局部变量仅在局部作用域内有效,不可以重复使用,不会造成变量污染。

闭包的坏处

1.闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,可能会导致内存泄露

解决这个问题的办法就是在不使用这些变量时,及时把不需要的局部变量全部删除

2.闭包会在父函数外部,改变父函数内部变量的值。

如果你把父函数当作对象使用,把闭包当作它的公用方法(Public),把内部变量当作它的私有属性(private)时,要小心不要随便改变父函数内部变量的值。

闭包会造成内存泄露?

不会,内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

闭包里面的变量明明就是我们需要的变量,凭什么说是内存泄露?

这个谣言是如何来的?因为 IE,IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量,这是 IE 的问题,不是闭包的问题

参考文章